#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "v_queue.h"

/*=======================
 * Getter functions
 *======================*/

bool v_queue_empty(v_queue_ptr_t queue)
{
    return (queue->size == 0);
}

uint32_t v_queue_size(v_queue_ptr_t queue)
{
    return queue->size;
}

v_data_ptr_t v_queue_front(v_queue_ptr_t queue)
{
    return !v_queue_empty(queue) ? queue->front->next->data_ptr : queue->front->data_ptr;
}

v_data_ptr_t v_queue_rear(v_queue_ptr_t queue)
{
    return queue->rear->data_ptr;
}

/*=====================
 * Setter functions
 *====================*/

vlib_status_t v_queue_push(v_queue_ptr_t queue, v_data_ptr_t data_ptr, uint32_t data_size, copy_data_f copy_data)
{
    v_queue_node_t* node = (v_queue_node_t* ) v_malloc(sizeof (v_queue_node_t));
    if (node == NULL) {
        return VLIB_ERROR;
    }

    node->data_ptr = (v_data_ptr_t) v_malloc(data_size);
    if (copy_data != NULL)
        copy_data(node->data_ptr, data_ptr);
    else
        memcpy(node->data_ptr, data_ptr, data_size);

    node->next = NULL;
    queue->rear->next = node;
    queue->rear = node;

    ++queue->size;

    return VLIB_OK;
}

vlib_status_t v_queue_pop(v_queue_ptr_t queue)
{
    if (queue->rear == queue->front) {
        return VLIB_ERROR;
    }
    
    v_queue_node_t *p = queue->front->next;
    queue->front->next = p->next;
    if (queue->rear == p) {
        queue->rear = queue->front;
    }

    v_free(p->data_ptr);
    v_free(p);

    --queue->size;

    return VLIB_OK;
}

void v_queue_clear(v_queue_ptr_t queue)
{
    while (!v_queue_empty(queue)) {
        v_queue_pop(queue);
    }
}

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

v_queue_ptr_t v_queue_create(uint32_t type_size)
{
    v_queue_ptr_t queue = (v_queue_ptr_t) v_malloc(sizeof (struct v_queue));
    if (queue == NULL) {
        return NULL;
    }
    v_queue_node_t* head = (v_queue_node_t* ) v_malloc(sizeof (v_queue_node_t));
    if (head == NULL) {
        return NULL;
    }
    head->data_ptr = (v_data_ptr_t) v_malloc(type_size); /* 为 head 节点分配空间：当 queue 为空的时候，确保正常访问 */
    memset(head->data_ptr, '\0', type_size);
    head->next = NULL;
    queue->front = queue->rear = head;
    queue->size = 0;

    return queue;
}

void v_queue_destroy(v_queue_ptr_t queue)
{
    v_queue_clear(queue);
    v_free(queue->front->data_ptr);
    v_free(queue->front);
    v_free(queue);
}

